package com.gzhryc.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.ConcurrentHashMap;

import javax.sql.DataSource;

import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.apache.commons.lang3.StringUtils;

import com.gzhryc.jdbc.enums.DbType;
import com.gzhryc.jdbc.models.ConnectInfo;

public class ConnectionFactory {

	private static String DefaultJdbcKey;
	
	private final static ConcurrentHashMap<String, WrapDataSource> store = new ConcurrentHashMap<String, WrapDataSource>();

	/**
	 * 添加数据源连接池
	 * @param key
	 * @param info
	 * @return
	 */
	public static boolean addDataSourcePool(String key,ConnectInfo info){
		try {
			DataSource dataSource = BasicDataSourceFactory
					.createDataSource(info.getProperties());
			info.setKey(key);
			store.put(key, new WrapDataSource(info, dataSource));
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
	
	/**
	 * 添加数据源
	 * @param key
	 * @param info
	 * @return
	 */
	public static boolean addDataSource(String key, ConnectInfo info) {
		try {
			info.setKey(key);
			store.put(key, new WrapDataSource(info));
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
	
	public static boolean addDataSource(String key,DbType dbType,DataSource dataSource) {
		try {
			ConnectInfo info = new ConnectInfo(dbType);
			info.setKey(key);
			store.put(key, new WrapDataSource(info,dataSource));
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
	
	/**
	 * 移除数据源
	 * @param key
	 */
	public static void removeDataSource(String key){
		if(key != null){store.remove(key);}
	}
	
	public static boolean addManageDataSource(String key,ConnectInfo info){
		try {
			String manageKey = createMessageKey(key);
			if (info.getDbType().equals(DbType.mysql)) {
				ConnectInfo temp = info.clone();
				temp.setDbName("information_schema");
				temp.setUrl(null);
				store.put(manageKey, new WrapDataSource(temp));
				return true;
			}else if(info.getDbType().equals(DbType.h2)){
				ConnectInfo temp = info.clone();
				DataSource dataSource = BasicDataSourceFactory.createDataSource(temp.getProperties());
				store.put(manageKey, new WrapDataSource(temp, dataSource));
				return true;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	public static boolean containsKey(String key){
		return store.containsKey(key);
	}
	
	public static String getDefaultJdbcKey() {
		return DefaultJdbcKey;
	}
	
	public static void setDefaultJdbcKey(String defaultJdbcKey) throws Exception {
		if(containsKey(defaultJdbcKey)) {
			DefaultJdbcKey = defaultJdbcKey;
		}else {
			throw new Exception();
		}
	}
	
	public static DbType getDbType(String key) {
		if(StringUtils.isNotBlank(key)){
			WrapDataSource dataSource = store.get(key);
			if(dataSource == null){
				String manageKey = createMessageKey(key);
				dataSource = store.get(manageKey);
			}
			return dataSource.getInfo().getDbType();
		}
		return null;
	}

	public static Connection getManageConn(String key) {
		try {
			if(StringUtils.isNotBlank(key)) {
				String manageKey = createMessageKey(key);
				WrapDataSource manageDataSource = store.get(manageKey);
				if (manageDataSource == null) {
					WrapDataSource dataSource = store.get(key);
					if (dataSource != null) {
						if(addManageDataSource(key,dataSource.getInfo())){
							manageDataSource = store.get(manageKey);
						}
					}
				}
				if (manageDataSource != null) {
					Connection conn = manageDataSource.getConnection();
					conn.setAutoCommit(true); // 默认自动提交事务
					return conn;
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static Connection getManageConn(){
		if(store.size() > 0) {
			WrapDataSource dataSource = store.values().iterator().next();
			return getManageConn(dataSource.getInfo().getKey());
		}
		return null;
	}
	
	/**
	 * 获取数据库连接
	 * 
	 * @return 已连接的数据库连接或NULL
	 * @throws SQLException 
	 */
	public static Connection getConn(String key,boolean isAutoCommit) throws SQLException{
		if(StringUtils.isNotBlank(key)) {
			WrapDataSource dataSource = store.get(key);
			if(dataSource != null) {
				Connection conn = dataSource.getConnection();
				conn.setAutoCommit(isAutoCommit);
				return conn;
			}
		}
		return null;
	}

	/**
	 * 获取默认的数据库连接
	 * 
	 * @return 已连接的数据库连接或NULL
	 * @throws SQLException 
	 */
	public static Connection getConn(boolean isAutoCommit) throws SQLException {
		if(store.size() > 0) {
			WrapDataSource dataSource = store.values().iterator().next();
			Connection conn = dataSource.getConnection();
			conn.setAutoCommit(isAutoCommit);
			return conn;
		}
		return null;
	}

	/**
	 * 关闭数据库连接
	 * 
	 * @param conn
	 *            要关闭的数据库连接
	 */
	public static void close(Connection conn) {
		try {
			if (conn != null) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 关闭数据库连接
	 * 
	 * @param conn
	 *            要关闭的数据库连接
	 */
	public static void close(Connection conn, ResultSet rs) {
		try {
			if (rs != null) {
				rs.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			close(conn);
		}
	}
	
	/**
	 * 获取连接信息
	 * @param key
	 * @return
	 */
	public static ConnectInfo getConnectInfo(String key) {
		if(StringUtils.isNotBlank(key)) {
			WrapDataSource dataSource = store.get(key);
			if(dataSource != null) {
				return dataSource.getInfo();
			}
		}
		return null;
	}
	
	protected static class WrapDataSource {

		private ConnectInfo info;
		private DataSource dataSource;

		public WrapDataSource(ConnectInfo info) throws ClassNotFoundException{
			this.info = info;
			Class.forName(info.getDriverClassName());
		}
		
		public WrapDataSource(ConnectInfo info, DataSource dataSource) {
			this.info = info;
			this.dataSource = dataSource;
		}

		public DataSource getDataSource() {
			return dataSource;
		}

		public ConnectInfo getInfo() {
			return info;
		}

		public Connection getConnection() throws SQLException {
			if(dataSource != null){
				return dataSource.getConnection();
			}else{
				return DriverManager.getConnection(info.getUrl(),info.getUserName(),info.getPassword());
			}
		}
	}
	
	private static String createMessageKey(String key){
		return key + "_manage_";
	}

	private ConnectionFactory(){
		//私有构造函数
	}
}
